(function () {
    "use strict"
    // 为对象设置不可枚举的属性
    var define = function define(obj, key, value) {
        Object.defineProperty(obj, key, {
            writable: true,
            configurable: true,
            enumerable: false,
            value: value
        })
    }
    // 确保是 Promise 类的实例
    var ensureInstance = function ensureInstance(obj) {
        if (!(obj instanceof Promise)) throw new TypeError("Method Promise.prototype.then called on incompatible receiver " + obj)
    }
    // 基于定时器模拟 queueMicrotask 创建异步微任务「我们创建的是异步宏任务」
    var queueTask = function queueTask(callback) {
        if (typeof queueMicrotask !== 'undefined') {
            return queueMicrotask(callback)
        }
        var timer = setTimeout(function () {
            callback()
            clearTimeout(timer)
        }, 0)
    }

    /* 构造函数 */
    var Promise = function Promise(executor) {
        var self = this
        if (!(self instanceof Promise)) throw new TypeError("Promise constructor cannot be invoked without 'new'")
        if (typeof executor !== 'function') throw new TypeError("Promise resolver undefined is not a function")

        // 为实例设置私有属性：状态和值
        define(self, 'state', 'pending')
        define(self, 'result', undefined)
        define(self, 'onfulfilledCallback', [])
        define(self, 'onrejectedCallback', [])

        // 修改实例状态和值
        var change = function change(state, result) {
            if (self.state !== 'pending') return //状态一但被更改过，则后续不能再更改了
            self.state = state
            self.result = result
            // 通知集合中的方法执行「异步微任务」
            queueTask(function () {
                var callbacks = self.state === 'fulfilled' ? self.onfulfilledCallback : self.onrejectedCallback
                callbacks.forEach(function (callback) {
                    callback(self.result)
                })
            })
        }

        // 立即执行 executor 函数
        try {
            executor(
                function resolve(value) {
                    change('fulfilled', value)
                },
                function reject(reason) {
                    change('rejected', reason)
                }
            )
        } catch (err) {
            // 如果 executor 函数执行报错，也会把实例的状态改为失败，值就是报错原因
            change('rejected', err)
        }
    }

    /* 原型对象 */
    var proto = Promise.prototype
    define(proto, 'then', function then(onfulfilled, onrejected) {
        var self = this
        ensureInstance(self)
        switch (self.state) {
            case 'fulfilled':
                queueTask(function () {
                    onfulfilled(self.result)
                })
                break
            case 'rejected':
                queueTask(function () {
                    onrejected(self.result)
                })
                break
            default:
                self.onfulfilledCallback.push(onfulfilled)
                self.onrejectedCallback.push(onrejected)
        }
    })

    /* 暴露API「支持各种环境」 */
    /* if (typeof window !== 'undefined') window.Promise = Promise
    if (typeof module === 'object' && typeof module.exports === 'object') module.exports = Promise */
})();

/*
 ES6中有一个属性 new.target ：存储被 new 的目标 
   + 普通函数执行，存储的值是 undefined
   + 构造函数执行，new.target 就是被 new 的那个构造函数

 ES6中新增一个 queueMicrotask 的API，目的：创建一个可执行的异步微任务
   queueMicrotask(() => {
      ...
   })
 */